import pandas as pd
import numpy as np
from .planner import basic_planner

class target_list(object):
    def __init__(self, operation_obj: basic_planner):
        self.__list = []
        self.__param_list = operation_obj.param_list()
        self.__param_num = len(self.__param_list)
        self.__param_dict = {}
        self.__update_param_dict()

    def __init__(self, targets, operation_obj: basic_planner):
        self.__param_list = operation_obj.param_list()
        self.__param_num = len(self.__param_list)
        self.__param_dict = {}
        self.__update_param_dict()

        if isinstance(targets, pd.core.frame.DataFrame):
            np_params  = np.array(targets[self.__param_list][1:] , dtype = np.float32)
            np_num = np.array([i + 1 for i in range(len(np_params))], dtype = int)
            np_list = np.insert(np_params, 0, np_num, axis=1)
            self.__list = np_list.tolist()
        elif isinstance(targets, np.ndarray):
            if len(targets[0]) == self.__param_num + 1:
                self.__list = targets.tolist()
            else:
                raise ValueError("Lenght of targets not matched.")
        elif isinstance(targets, list):
            if len(targets[0]) == self.__param_num + 1:
                self.__list = targets
            else:
                raise ValueError("Lenght of targets not matched.")
        else:
            raise TypeError("Type of targets not matched.")
    
    def __update_param_dict(self):
        self.__param_dict = {}
        for i, param_name in enumerate(self.__param_list):
            self.__param_dict[param_name] = i
    
    def extend(self, params):
        if not isinstance(params, list):
            raise TypeError("Type of params should be list.")
        if len(params) == self.__param_num:
            self.__list.extend([len(self.__list)] + params)
        else:
            raise ValueError("Lenght of params not matched.")

    def add_row(self, row_name, params):
        if not isinstance(row_name, str):
            raise TypeError("Type of row_name should be string.")
        if not isinstance(params, list):
            raise TypeError("Type of params should be list.")
        self.__param_list.append(row_name)
        self.__param_num = len(self.__param_list)
        if len(params) != len(self.__list):
            raise ValueError("Lenght of params not matched.")
        for i in range(len(self.__list)):
            self.__list[i] += [params[i]]

        self.__update_param_dict()

    def add_rows(self, row_name, params):
        if not isinstance(row_name, list):
            raise TypeError("Type of row_name should be list.")
        if not isinstance(params, list):
            raise TypeError("Type of params should be list.")
        if len(row_name) != len(params[0]):
            raise ValueError("Lenght of row_name and params not matched.")
        self.__param_list += row_name
        self.__param_num = len(self.__param_list)
        if len(params) != len(self.__list):
            raise ValueError("Lenght of params not matched.")
        for i in range(len(self.__list)):
            self.__list[i] += params[i]

        self.__update_param_dict()

    def find_target_index(self, id: int):
        index = np.where(np.array(self.__list)[:,0] == id)[0][0]
        return index
    
    def find_target(self, id: int):
        index = self.find_target_index(id)
        return self.__list[index]

    def delete_target(self, id: int):
        index = np.where(np.array(self.__list)[:,0] == id)[0][0]
        del self.__list[index]

    def __getitem__(self, key):
        return self.__list[key]
    
    def __setitem__(self, key, value):
        self.__list[key] = value

    @property
    def len(self):
        return len(self.__list)

    @property
    def nplist(self):
        return np.array(self.__list)

    @property
    def list(self):
        return self.__list

    @property
    def param_list(self):
        return self.__param_list

    @property
    def param_index(self, param_name):
        if param_name in self.__param_dict.keys():
            return self.__param_dict[param_name]
        else:
            raise ValueError(f"Param {param_name} not found!")
